import { ElTable, ElTableColumn, ElImage, ElLoading } from 'element-plus';
import { StatusLabel } from '@/components/StatusLabel';
import { defineComponent, ref, computed } from 'vue';
import { proTableProps, ProTableProps, ITableColumnsItem } from './types';
import xss from 'xss';
import dayjs from 'dayjs';
import { extractAttrsEvent } from '@/core/utils/install';

export default defineComponent({
  name: 'ProTable',
  directives: { loading: ElLoading.directive },
  props: proTableProps,
  setup(props) {
    const elementRef = ref<InstanceType<typeof ElTable>>();
    const noop = () => {
      throw new Error('无法调用element对应方法，请检查组件ref属性是否绑定元素');
    };
    const itemDefaultRender = (row: any, column: ProTableProps['columns'][0]) => {
      const { format = 'YYYY-MM-DD', prop, options = [], mode, dot } = column;
      if (!prop) return null;
      let text = row[prop];
      switch (column.type) {
        case 'date':
          text = dayjs(text).format(format);
          break;
        case 'enum':
          text = <StatusLabel options={options} value={text} mode={mode} dot={dot} />;
          break;
        default:
          break;
      }
      if ((column.ellipsis || column.showOverflowTooltip) && typeof text === 'string') {
        text = xss(text);
      }
      return text;
    };
    const itemImgRender = (row: any, column: ProTableProps['columns'][0]) => {
      if (!column.prop) return null;
      return (
        <ElImage
          src={row[column.prop]}
          preview-src-list={[row[column.prop]]}
          style={{
            width: '60px',
            height: '60px',
            borderRadius: '4px',
          }}
          fit="cover"
          lazy
          preview-teleported
        />
      );
    };
    const clearSelection = computed(() => elementRef.value?.clearSelection ?? noop);
    const getSelectionRows = computed(() => elementRef.value?.getSelectionRows ?? noop);
    const toggleRowSelection = computed(() => elementRef.value?.toggleRowSelection ?? noop);
    const toggleAllSelection = computed(() => elementRef.value?.toggleAllSelection ?? noop);
    const toggleRowExpansion = computed(() => elementRef.value?.toggleRowExpansion ?? noop);
    const setCurrentRow = computed(() => elementRef.value?.setCurrentRow ?? noop);
    const clearSort = computed(() => elementRef.value?.clearSort ?? noop);
    const clearFilter = computed(() => elementRef.value?.clearFilter ?? noop);
    const doLayout = computed(() => elementRef.value?.doLayout ?? noop);
    const sort = computed(() => elementRef.value?.sort ?? noop);
    const scrollTo = computed(() => elementRef.value?.scrollTo ?? noop);
    const setScrollTop = computed(() => elementRef.value?.setScrollTop ?? noop);
    const setScrollLeft = computed(() => elementRef.value?.setScrollLeft ?? noop);
    return {
      clearSelection,
      getSelectionRows,
      toggleRowSelection,
      toggleAllSelection,
      toggleRowExpansion,
      setCurrentRow,
      clearSort,
      clearFilter,
      doLayout,
      sort,
      scrollTo,
      setScrollTop,
      setScrollLeft,
      elementRef,
      itemDefaultRender,
      itemImgRender,
    };
  },
  render() {
    const renderColumn = (columns: ITableColumnsItem<any>[]) => {
      return columns.map((v) => {
        const {
          label = '',
          ellipsis = false,
          showOverflowTooltip = false,
          children = [],
          renderHeader,
          render,
          type,
          isHidden,
          ...rest
        } = v;
        if (isHidden) return null;
        return (
          <ElTableColumn
            {...rest}
            label={label}
            type={type}
            key={JSON.stringify(v)}
            show-overflow-tooltip={ellipsis || showOverflowTooltip}
            v-slots={{
              default:
                type && ['selection', 'index'].includes(type)
                  ? undefined
                  : ({ row, $index, column }: any) => {
                      if (children.length === 0 && $index === -1) return null;
                      if (children.length > 0) return renderColumn(children);
                      if (render) return render(row, column, $index);
                      if (v.prop) {
                        if (type === 'image') return this.itemImgRender(row, v);
                        return this.itemDefaultRender(row, v);
                      }
                      return undefined;
                    },
              header: ({ $index, column }: any) => <>{renderHeader ? renderHeader(column, $index) : label}</>,
            }}
          />
        );
      });
    };
    const { columns, loading, ...rest } = this.$props;
    const attrs = extractAttrsEvent(this.$attrs);
    return (
      <>
        <ElTable
          {...rest}
          {...attrs}
          ref="elementRef"
          v-loading={loading}
          v-slots={{
            empty: this.$slots.empty,
          }}
        >
          {renderColumn(columns)}
        </ElTable>
      </>
    );
  },
});
